#include "Ogre.h"

#include "EngineManager.h"
#include "EntityManager.h"
#include "GUIManager.h"
#include "InputHandler.h"
#include "Simulation.h"
#include "Player.h"

OgreEngineManager::OgreEngineManager(){ }
OgreEngineManager::~OgreEngineManager(){ }

bool OgreEngineManager::Startup()
{
	root = new Ogre::Root("","");

#ifdef _DEBUG
    root->loadPlugin("RenderSystem_Direct3D9_d");
#else
    root->loadPlugin("RenderSystem_Direct3D9");
#endif
 
    Ogre::RenderSystemList renderSystems;
    Ogre::RenderSystemList::iterator r_it;
 
    // we do this step just to get an iterator that we can use with setRenderSystem. In a future article
    // we actually will iterate the list to display which renderers are available. 
	renderSystems = root->getAvailableRenderers();
    r_it = renderSystems.begin();
    root->setRenderSystem(*r_it);
    root->initialise(false);
	
    // load common plugins
#ifdef _DEBUG
//    root->loadPlugin("Plugin_CgProgramManager_d");        
    root->loadPlugin("Plugin_OctreeSceneManager_d");
#else
  //  root->loadPlugin("Plugin_CgProgramManager");        
    root->loadPlugin("Plugin_OctreeSceneManager");
#endif
    // load the basic resource location(s)
    Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
        "resource", "FileSystem", "General");
    Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
        "resource/MyGUI_Media", "FileSystem", "GUI");
#ifdef WIN32
    Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
        "c:\\windows\\fonts", "FileSystem", "GUI");
#endif
 
    Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("General");
    Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("GUI");
 
    // setup main window; hardcode some defaults for the sake of presentation
    Ogre::NameValuePairList opts;
    opts["resolution"] = "1024x768";
    opts["fullscreen"] = "false";
    opts["vsync"] = "false";

    // create a rendering window with our title
    window = root->createRenderWindow("FlieBob Project", 1024, 768, false, &opts);
 
    // we can use the ST_GENERIC scene manager for now
    // in a later article we'll see how to change this
	sceneMgr = root->createSceneManager(Ogre::ST_GENERIC, (Ogre::String)"DEFAULT");
    
	genericCamera = sceneMgr->createCamera("camera");
    genericCamera->setNearClipDistance(1);

    Ogre::Viewport* vp = window->addViewport(genericCamera);
	vp->setBackgroundColour(Ogre::ColourValue::Black);
 
    // most examples get the viewport size to calculate this; for now, we'll just 
    // set it to 4:3 the easy way
    genericCamera->setAspectRatio((Ogre::Real)1.333333);
 
    // this next bit is for the sake of the input handler
    unsigned long hWnd;
    window->getCustomAttribute("WINDOW", &hWnd);
 
    sim = new Simulation();
    // set up the InputHandler
    input = new InputHandler(sim, hWnd);
	input->setWindowExtents(1024, 768);

    // set up the Player
	Player::Instance().Startup(sceneMgr, input, sim);
	
	// set up the GUIManager
	GUIManager::Instance().Startup(window, sceneMgr);

	// start up the EntityManager, and prepare it to receive entities for collision checking
	EntityManager::Instance().Startup(sceneMgr, Ogre::Vector3(0, -9.81, 0), 
		Ogre::AxisAlignedBox( Ogre::Vector3 (-10000, -10000, -10000), //aligned box for Bullet
							  Ogre::Vector3 (10000,  10000,  10000)) );

	//root->addFrameListener(EntityManager::Instance());
	root->addFrameListener(this);
	WindowEventUtilities::addWindowEventListener(window, this);

	return true;
}

void OgreEngineManager::CreateScene()
{
	sceneMgr->setAmbientLight(Ogre::ColourValue(0.7, 0.7, 0.7));

	Ogre::Plane plane(Ogre::Vector3::UNIT_Y, 0);

	Ogre::MeshManager::getSingleton().createPlane("FloorPlane", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
        plane, 200000, 200000, 20, 20, true, 1, 2000, 2000, Ogre::Vector3::UNIT_Z);

	Ogre::Entity* entGround = sceneMgr->createEntity("GroundEntity", "FloorPlane");
    sceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(entGround);
	
	entGround->setMaterial(MaterialManager::getSingleton().getByName("Grass/Grass_Floor"));
    entGround->setCastShadows(false);

	sceneMgr->setSkyDome(true, "Sky/CloudySky", 50, 8);

	sceneMgr->setShadowTechnique(SHADOWTYPE_STENCIL_ADDITIVE);

	Light* light = sceneMgr->createLight("light01");
	light->setType(Light::LT_DIRECTIONAL);
	light->setDiffuseColour(0.5,0.5,0.4);
	light->setDirection(1,-1,1);
}

bool OgreEngineManager::frameStarted(const FrameEvent &evt)
{
	input->capture();

	EntityManager::Instance().StepSimulation(evt.timeSinceLastFrame);

	return true;
}

bool OgreEngineManager::frameEnded(const FrameEvent &evt)
{
	EntityManager::Instance().StepSimulation(evt.timeSinceLastFrame);

	return true;
}

void OgreEngineManager::Shutdown()
{	
	root->removeFrameListener(this);
	root->removeFrameListener((Ogre::FrameListener *) &Player::Instance());

	Player::Instance().Shutdown();
	EntityManager::Instance().Shutdown();
	GUIManager::Instance().Shutdown();

	delete input;
    delete sim;
    delete root;
}